#!/usr/bin/env python
# -*- coding: utf-8 -*-

import cherrypy

from farado.logger import logger
from farado.ui.renderer import view_renderer
from farado.helpers.cookie_helper import current_session_id
from farado.general_manager_holder import project_manager
from farado.items.role import Role
from farado.items.rule import Rule
from farado.items.menu_item import MenuItem
from farado.ui.operation_result import OperationResult
from farado.ui.base_view import BaseView, UiUserRestrictions
from farado.ui.base_view import bring_value, get_value


class RolesView(BaseView):

    #--------------------------------------------------------------------------#
    def __init__(self):
        super().__init__()
        self.name = '/roles'

    #--------------------------------------------------------------------------#
    @cherrypy.expose
    def index(self):
        user = self.current_user()
        if not user:
            return self.login_and_open()

        is_admin = self.is_admin(user.id)
        if not is_admin:
            message = f"Нет доступа к перечню ролей пользователей."
            logger.warn(f"%-18s | {message}", user.login)
            raise cherrypy.HTTPError(403, message)

        message = f"Открытие страницы с перечнем ролей."
        logger.info(f"%-18s | {message}", user.login)

        return view_renderer["roles"].render(
            user=user,
            project_manager=project_manager(),
            operation_result=user.pop_last_action_result(),
            restriction=UiUserRestrictions(
                is_admin=is_admin,
            )
        )

    #--------------------------------------------------------------------------#
    @cherrypy.expose
    def role(self, target_role_id=None, **args):
        user = self.current_user()
        if not user:
            if target_role_id:
                return self.login_and_open(f'/role/{target_role_id}', args)
            return self.login_and_open()

        args = bring_value(user.pop_last_action_data(), args)
        target_role_caption = get_value(args, 'target_role_caption', None)
        target_role_icon = get_value(args, 'target_role_icon', None)

        is_admin = self.is_admin(user.id)
        if not is_admin:
            message = f"Нет доступа к роли #{target_role_id}."
            logger.warn(f"%-18s | {message}", user.login)
            raise cherrypy.HTTPError(403, message)

        target_role = project_manager().role(target_role_id)

        operation_result = user.pop_last_action_result()
        if target_role_caption:
            if not target_role:
                target_role = Role()

                message = f"Создание роли «{target_role_caption}»."
                logger.info(f"%-18s | {message}", user.login)

            # Prepare rules property values
            rules_properties = {}
            for key, value in args.items():
                key_data = key.split("_")
                rule_id = key_data[-1]
                if not rule_id.isdigit():
                    continue
                rule_field = "_".join(key_data[1:-1])
                if not rule_id in rules_properties:
                    rules_properties[rule_id] = {}
                rules_properties[rule_id][rule_field] = value

            # Apply rules property changes
            for rule_id, properties in rules_properties.items():
                rule = project_manager().rule(rule_id)
                rule.reset_properties(properties)
                rule.role_id = target_role_id
                project_manager().save_item(rule)

            # Remove deleted rules
            for rule in project_manager().rules_by_role(target_role_id):
                if str(rule.id) in rules_properties:
                    continue
                project_manager().remove_item(Rule, rule.id)

            target_role.caption = target_role_caption
            target_role.icon = target_role_icon
            project_manager().save_item(target_role)
            operation_result = OperationResult(
                caption="Роль сохранена",
                kind="success",
            )

            message = f"Роль #{target_role_id} сохранена."
            logger.info(f"%-18s | {message}", user.login)

        message = f"Открытие страницы роли #{target_role_id}."
        logger.info(f"%-18s | {message}", user.login)

        return view_renderer["role"].render(
            user=user,
            target_role=target_role,
            project_manager=project_manager(),
            operation_result=operation_result,
            restriction=UiUserRestrictions(
                is_admin=is_admin,
            )
        )

    #--------------------------------------------------------------------------#
    @cherrypy.expose
    def add_role(self):
        user = self.current_user()
        if not user:
            return self.login_and_open('/add_role')

        is_admin = self.is_admin(user.id)
        if not is_admin:
            message = f"Нет доступа для создания роли."
            logger.warn(f"%-18s | {message}", user.login)
            raise cherrypy.HTTPError(403, message)

        message = f"Открытие страницы создания роли."
        logger.info(f"%-18s | {message}", user.login)

        return view_renderer["role"].render(
            user=user,
            target_role=None,
            project_manager=project_manager(),
            save_result=None,
            restriction=UiUserRestrictions(
                is_admin=is_admin,
            )
        )

    #--------------------------------------------------------------------------#
    @cherrypy.expose
    def remove_role(self, target_role_id):
        user = self.current_user()
        if not user:
            return self.login_and_open(f'/remove_role/{target_role_id}')

        is_admin = self.is_admin(user.id)
        if not is_admin:
            message = f"Нет доступа для удаления роли #{target_role_id}."
            logger.warn(f"%-18s | {message}", user.login)
            raise cherrypy.HTTPError(403, message)

        project_manager().remove_item(Role, target_role_id)

        message = f"Роль #{target_role_id} удалена."
        logger.info(f"%-18s | {message}", user.login)

        user.push_last_action_result(
            OperationResult(
                caption="Роль удалена",
                kind="success"
            )
        )
        raise cherrypy.HTTPRedirect(cherrypy.url(f'/'))

    #--------------------------------------------------------------------------#
    @cherrypy.expose
    def add_rule(self, target_role_id):
        user = self.current_user()
        if not user:
            return self.login_and_open(f'/add_rule/{target_role_id}')

        is_admin = self.is_admin(user.id)
        if not is_admin:
            message = f"Нет доступа для добавления правила к роли #{target_role_id}."
            logger.warn(f"%-18s | {message}", user.login)
            raise cherrypy.HTTPError(403, message)

        if not project_manager().role(target_role_id):
            message = f"Роль #{target_role_id} не найдена."
            logger.warn(f"%-18s | {message}", user.login)
            raise cherrypy.HTTPError(404, message)

        rule = Rule()
        rule.role_id = target_role_id
        project_manager().save_item(rule)

        message = f"Новое правило добавлено роли #{target_role_id}."
        logger.info(f"%-18s | {message}", user.login)

        user.push_last_action_result(
            OperationResult(
                caption="Правило добавлено",
                kind="success",
                tab_name="rules",
            )
        )
        raise cherrypy.HTTPRedirect(cherrypy.url(f'/role/{target_role_id}'))

    #--------------------------------------------------------------------------#
    @cherrypy.expose
    def add_menu_item(self, target_role_id):
        user = self.current_user()
        if not user:
            return self.login_and_open(f'/add_menu_item/{target_role_id}')

        is_admin = self.is_admin(user.id)
        if not is_admin:
            message = f"Нет доступа для добавления пункта меню к роли #{target_role_id}"
            logger.warn(f"%-18s | {message}", user.login)
            raise cherrypy.HTTPError(403, message)

        if not project_manager().role(target_role_id):
            message = f"Роль #{target_role_id} не найдена."
            logger.warn(f"%-18s | {message}", user.login)
            raise cherrypy.HTTPError(404, message)

        menu_item = MenuItem()
        menu_item.role_id = target_role_id
        project_manager().save_item(menu_item)

        message = f"Новый пункт меню добавлен роли #{target_role_id}."
        logger.info(f"%-18s | {message}", user.login)

        user.push_last_action_result(
            OperationResult(
                caption="Пункт меню для роли добавлен",
                kind="success",
                tab_name="menu_item",
            )
        )
        raise cherrypy.HTTPRedirect(cherrypy.url(f'/role/{target_role_id}'))

    #--------------------------------------------------------------------------#
    @cherrypy.expose
    def save_menu_item(self, target_role_id, menu_item_id, **args):
        user = self.current_user()
        if not user:
            return self.login_and_open(
                f'/save_menu_item/{target_role_id}/{menu_item_id}', args
            )

        is_admin = self.is_admin(user.id)
        if not is_admin:
            message = f"Нет доступа для изменения пункта меню #{menu_item_id} роли #{target_role_id}."
            logger.warn(f"%-18s | {message}", user.login)
            raise cherrypy.HTTPError(403, message)

        args = bring_value(user.pop_last_action_data(), args)

        target_role = project_manager().role(target_role_id)
        if not target_role:
            message = f"Роль #{target_role_id} не найдена."
            logger.warn(f"%-18s | {message}", user.login)
            raise cherrypy.HTTPError(404, message)

        menu_item = target_role.menu_item(menu_item_id)
        if not menu_item:
            message = f"Пункт меню #{menu_item_id} не найден."
            logger.warn(f"%-18s | {message}", user.login)
            raise cherrypy.HTTPError(404, message)

        menu_item.caption = get_value(args, 'menu_item_caption', menu_item.caption)
        menu_item.link = get_value(args, 'menu_item_link', menu_item.link)
        menu_item.icon = get_value(args, 'menu_item_icon', menu_item.icon)
        project_manager().save_item(menu_item)

        message = f"Пункт меню #{menu_item_id} сохранён в роли #{target_role_id}."
        logger.info(f"%-18s | {message}", user.login)

        user.push_last_action_result(
            OperationResult(
                caption="Пункт меню для роли изменён",
                kind="success",
                tab_name="menu_item",
            )
        )
        raise cherrypy.HTTPRedirect(cherrypy.url(f'/role/{target_role_id}'))

    #--------------------------------------------------------------------------#
    @cherrypy.expose
    def remove_menu_item(self, target_role_id, menu_item_id):
        user = self.current_user()
        if not user:
            return self.login_and_open(
                f'/remove_menu_item/{target_role_id}/{menu_item_id}'
            )

        is_admin = self.is_admin(user.id)
        if not is_admin:
            message = f"Нет доступа для удаления пункта меню."
            logger.warn(f"%-18s | {message}", user.login)
            raise cherrypy.HTTPError(403, message)

        project_manager().remove_item(MenuItem, menu_item_id)

        message = f"Пункт меню #{menu_item_id} удалён из роли #{target_issue_kind_id}."
        logger.info(f"%-18s | {message}", user.login)

        user.push_last_action_result(
            OperationResult(
                caption="Пункт меню для роли удалён",
                kind="success",
                tab_name="menu_item",
            )
        )
        raise cherrypy.HTTPRedirect(cherrypy.url(f'/role/{target_role_id}'))
